// ConditionNode.java
package org.zjx.core.nodes;

import lombok.Data;
import org.zjx.core.DecisionContext;
import org.zjx.core.DecisionNode;
import org.zjx.core.DecisionStack;
import org.zjx.core.GameAction;
import org.zjx.core.state.StateAccessor;

import java.util.Map;
import java.util.function.BiPredicate;

/**
 * 条件分支节点 - 根据条件选择不同分支的决策节点
 *
 * 功能说明：
 * 1. 封装一个条件判断逻辑
 * 2. 根据条件结果选择执行true分支或false分支
 * 3. 支持基于状态访问器或决策上下文的灵活条件判断
 *
 * 使用场景：
 * - 当需要根据游戏状态决定不同行为路径时使用
 * - 可以嵌套在其他节点中构建复杂的决策逻辑
 */
@Data
public class ConditionNode implements DecisionNode {
    /**
     * 条件判断函数
     * 接受状态访问器和本地参数，返回布尔值
     * 不可为null，必须在构造时提供有效的BiPredicate
     */
    private BiPredicate<StateAccessor, Map<String, Object>> condition;

    /**
     * 条件为真时执行的分支节点
     * 可以为null，表示条件为真时不执行任何操作
     */
    private DecisionNode trueBranch;

    /**
     * 条件为假时执行的分支节点
     * 可以为null，表示条件为假时不执行任何操作
     */
    private DecisionNode falseBranch;

    /**
     * 构造函数
     * @param condition 条件判断函数(不可为null)
     * @param trueBranch 条件为真时的分支节点
     * @param falseBranch 条件为假时的分支节点
     * @throws IllegalArgumentException 如果condition参数为null
     */
    public ConditionNode(BiPredicate<StateAccessor, Map<String, Object>> condition,
                         DecisionNode trueBranch, DecisionNode falseBranch) {
        if (condition == null) {
            throw new IllegalArgumentException("Condition cannot be null");
        }
        this.condition = condition;
        this.trueBranch = trueBranch;
        this.falseBranch = falseBranch;
    }

    /**
     * 执行决策逻辑
     * @param context 决策上下文，包含状态访问器和本地参数
     * @return 如果条件为真且trueBranch不为null则返回trueBranch的执行结果，
     *         如果条件为假且falseBranch不为null则返回falseBranch的执行结果，
     *         否则返回null
     *
     * 方法行为：
     * 1. 执行条件判断
     * 2. 根据条件结果选择分支
     * 3. 如果有下一个节点，将节点压入调用栈
     * 4. 返回分支节点的执行结果(可能为null)
     */
    @Override
    public GameAction decide(DecisionContext context) {
        // 执行条件判断，传入状态访问器和本地参数
        boolean result = condition.test(
                context.getStateAccessor(),
                context.getLocalParams()
        );

        // 根据条件结果选择分支
        DecisionNode next = result ? trueBranch : falseBranch;

        if (next != null) {
            GameAction action = next.decide(context);
            if (action != null) {
                return action;  // 如果分支返回动作，直接返回
            }

            // 如果分支返回null，将下一个节点压入调用栈
            context.getCallStack().push(new DecisionStack.Frame(
                    next,
                    context.getStateAccessor()
            ));
        }
        return null;  // 条件节点不直接返回动作，只控制流程
    }
}